package com.sinsz.nacos.listener;

import com.sinsz.nacos.annotation.NacosAutowired;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.lang.NonNull;
import org.springframework.util.ObjectUtils;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

/**
 * 配置缓存
 * @author chenjianbo
 * @date 2019-1-29
 */
public final class Cache {

    private Cache() {
    }

    private static ApplicationContext context = null;

    /**
     * 设置上下文
     * @param context
     */
    public static void setContext(@NonNull ApplicationContext context) {
        Cache.context = context;
    }

    /**
     * 配置信息缓存
     * <p>
     *     配置中心的配置缓存
     * </p>
     */
    static Map<String, Object> property = new TreeMap<>();

    /**
     * 扫描到的所有类缓存
     * <p>
     *     用于注解@NacosLoader配合使用得到
     * </p>
     */
    public static List<Class<?>> allClasses = new ArrayList<>();

    /**
     * 实现动态赋值
     */
    synchronized static void updateAutowired() {
        if (ObjectUtils.isEmpty(allClasses)) {
            return;
        }
        allClasses.stream()
                .filter(clz -> {
                    if (Cache.context == null) {
                        return false;
                    }
                    try {
                        Object c = Cache.context.getBean(clz);
                        Field[] fields = c.getClass().getDeclaredFields();
                        boolean status = false;
                        for (Field field : fields) {
                            NacosAutowired nacosAutowired = field.getAnnotation(NacosAutowired.class);
                            if (nacosAutowired != null) {
                                status = true;
                                break;
                            }
                        }
                        return status;
                    } catch (BeansException e) {
                        return false;
                    }
                })
                .forEach(clz -> {
                    Object c = Cache.context.getBean(clz);
                    Field[] fields = c.getClass().getDeclaredFields();
                    for (Field field : fields) {
                        try {
                            NacosAutowired nacosAutowired = field.getAnnotation(NacosAutowired.class);
                            if (nacosAutowired != null) {
                                field.setAccessible(true);
                                field.set(c, fetch(field.getType()));
                            }
                        } catch (IllegalAccessException e) {
                            e.printStackTrace(System.err);
                        }
                    }
                });
    }

    /**
     * 获取缓存值
     * <p>
     *     获取缓存配置数据；
     *     非注入模式获取数据（代码模式使用）
     *     示例：VideoRoomProperties prop = Cache.fetch(VideoRoomProperties.class);
     * </p>
     * @param tClass
     * @param <T>
     * @return
     */
    public synchronized static <T> T fetch(Class<T> tClass) {
        try {
            if (tClass != null) {
                T t = tClass.newInstance();
                Object source = property.get(tClass.getName());
                if (source == null) {
                    return null;
                }
                BeanUtils.copyProperties(source, t);
                return t;
            }
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace(System.err);
        }
        return null;
    }

}
